package gdca.webservice.common;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class XmlParse {
	private Document dom = null;
	//private static Log log = LogFactory.getLog(XmlParse.class);
	private static SAXReader reader = new SAXReader();
	private Element root = null;
	private Map<String, List> mpListCach = new HashMap<String, List>();
	private Map<String, XMLData> mpNodeCach = new HashMap<String, XMLData>();
	
	public XmlParse(InputStream stream) throws Exception{
		try{
			dom = reader.read(stream);
		}catch(DocumentException de){
			//log.debug("parse xml error \n" + de.getMessage());
			throw new Exception(de);
		}
		root = dom.getRootElement();
	}

	public XmlParse(String xml, String encoding) throws Exception{
		try{
			byte[] bytes = xml.getBytes(); 
			InputStream in = new ByteArrayInputStream(bytes); 
			if(encoding==null)
			{
				encoding ="GBK";
			}
			InputStreamReader strInStream = new InputStreamReader(in, encoding);
			
			dom = reader.read(strInStream);
		}catch(DocumentException de){
			//log.debug("parse xml error:",de);
			throw new Exception(de);
		} catch (UnsupportedEncodingException e) {
			//log.debug("parse xml error:",e);
			throw new Exception(e);
		} 
		root = dom.getRootElement();
	}
	
	public XmlParse(File file) throws FileNotFoundException, Exception{
		if (!file.exists()){
			throw new FileNotFoundException();
		}
		try{
			dom = reader.read(file);
		}catch(DocumentException ex){
			//log.debug("parse xml file " + file.getAbsolutePath() + " error \n" + ex.getMessage());
			throw new Exception(ex);
		}
		root = dom.getRootElement();
	}
	
	public List<XMLData> getTreeByXPath(String name){
		List<XMLData> ltTmp = mpListCach.get(name);
		if (ltTmp != null){
			return ltTmp;
		}else {
			List<XMLData> ltData = this.getTree(name);
			mpListCach.put(name, ltData);
			return ltData;
		}
	}
	
	/**
	 * 找出符合给出的路径下的所有结点和所有子结点的数据,路径从根元素开始
	 * @param name
	 * @return
	 */
	private List<XMLData> getTree(String name){
		List<Element> ltTmp = new ArrayList<Element>();
		ltTmp.add(root);
		String[] pathArr = parsePath(name);
		List<Element> ltElement = getTreeList(ltTmp,pathArr,0);//找出路径最未级所在的所有结点
		Iterator itEle = ltElement.iterator();
		List<XMLData> ltData = new ArrayList<XMLData>();
		while (itEle.hasNext()){
			XMLData data = new XMLData();
			Element element = (Element)itEle.next();
			if (!element.getName().equals(pathArr[pathArr.length - 1])){
				continue;
			}
			data.setTagName(element.getName());
			data.setIndex(pathArr.length);
			data.setValue(element.getTextTrim());
			Iterator itAttr = element.attributes().iterator();
			Map<String, String> mpAttr = new HashMap<String, String>();
			while(itAttr.hasNext()){
				Attribute attr = (Attribute)itAttr.next();
				mpAttr.put(attr.getName(), attr.getValue());
			}
			data.setAttribute(mpAttr);
			data.setChildren(element.elements());//先把子元素保存在children，方便递归查找
			ltData.add(data);
		}
		return getDataList(ltData);
	}

	/**
	 * 找出符合给出的路径下唯一的结点和所有子结点的数据,路径从根元素开始
	 * @param name
	 * @return
	 */
	public XMLData getOnlyNodeByXPath(String name){
		Object objTmp = mpNodeCach.get(name);
		if (objTmp != null){
			return (XMLData)objTmp;
		}
		Iterator <XMLData> itData = this.getTreeByXPath(name).iterator();
		String[] paths = this.parsePath(name);
		XMLData tmp = null;
		while(itData.hasNext()){
			XMLData data = itData.next();
			if (data.getTagName().equals(paths[paths.length - 1])){
				tmp = data;
				break;
			}
		}
		mpNodeCach.put(name, tmp);
		return tmp;
	}
	
	/**
	 * 找出路径最未级所在的所有结点
	 * @param ltEle
	 * @param pathArr
	 * @param currentInd
	 * @return
	 */
	private List<Element> getTreeList(List<Element> ltEle,String[] pathArr, int currentInd){
		Iterator itTmp = ltEle.iterator();
		List<Element> ltTmp = new ArrayList<Element>();
		while(itTmp.hasNext()){
			Element tmp = (Element)itTmp.next();
			if (tmp.getName().equals(pathArr[currentInd])){//如果当前结点名符合要查找的路径中就保存
				ltTmp.addAll(tmp.elements());
			}
		}
		if (pathArr.length == currentInd + 1){//判断是否到了要找的路径的最未级了
			return ltEle;
		}else{
			return getTreeList(ltTmp, pathArr, currentInd + 1);//还没有到要查找的路径的最未级就继续递归查找
		}
	}
	
	/**
	 * 递归将xml的所有结点的数据放到
	 * @param ltData
	 * @return
	 */
	private List getDataList(List ltData){
		Iterator itTmp = ltData.iterator();
		while(itTmp.hasNext()){
			XMLData data = (XMLData)itTmp.next();
			Iterator itChi = data.getChildren().iterator();
			List<XMLData> ltTmp = new ArrayList<XMLData>();
			while(itChi.hasNext()){
				Element element = (Element)itChi.next();
				XMLData tmpData = new XMLData();
				tmpData.setTagName(element.getName());
				tmpData.setIndex(data.getIndex() + 1);
				tmpData.setValue(element.getTextTrim());
				Map<String, String> mpAttr = new HashMap<String, String>();
				//获取结点的属性值
				Iterator itAttr = element.attributes().iterator();
				while(itAttr.hasNext()){
					Attribute attr = (Attribute)itAttr.next();
					mpAttr.put(attr.getName(), attr.getValue());
				}
				tmpData.setAttribute(mpAttr);
				tmpData.setChildren(element.elements());
				ltTmp.add(tmpData);
			}
			if (ltTmp.size() > 0){
				data.setChildren(getDataList(ltTmp));
			}
		}
		
		return ltData;
	}
	
	private String[] parsePath(String path){
		//path = path.replaceAll("\\", "/");
		path = (path.startsWith("/"))? path.substring(1):path;
		path = (path.endsWith("/"))? path.substring(0, path.lastIndexOf("/")):path;
		String[] pathArr = path.split("/");
		return pathArr;
	}
	
	public void test(List ltData){
		Iterator itData = ltData.iterator();
		while (itData.hasNext()){
			XMLData data = (XMLData)itData.next();
			System.out.println(data.getTagName());
			System.out.println(data.getIndex());
			System.out.println(data.getValue());
			if (data.getAttribute() != null){
				Iterator itKey = data.getAttribute().keySet().iterator();
				while(itKey.hasNext()){
					System.out.println(data.getAttribute().get(itKey.next()));
				}
			}
			if (data.getChildren().size() > 0){
				test(data.getChildren());
			}
		}
	}
}
